package org.jfsm.core;

class FSMWorker {

    static final int END_OF_TRANSITION = -1;
    static final int SESSION_SIGNAL = -2;

    protected final FSMLogger logger;

    final int initStateID, endStateID;
    private final Transition[][] tMap;

    Object nextMessage;
    FSMReplyContext replyCtx;

    FSMWorker(BaseTransitionMap<?> tm) throws FSMException {
        logger = tm.logger;

        initStateID = tm.getInitStateID();
        endStateID = tm.getEndStateID();
        tMap = tm.tMap;
        logger.created(this);
    }

    void submit(InstanceState context, int eventID, Object message) {
        run(context, eventID, message);
    }

    Object createWork(int eventID, Object message) {
        return null;
    }

    void submit(InstanceState context, Object work) {
    }

    protected final void run(InstanceState context, int eventID, Object message) {

        int stateID = context.getStateID();

        if (eventID >= 0) {
            nextMessage = message;
            logger.event(context, stateID, eventID, message);
        } else if (eventID == SESSION_SIGNAL) {
            SessionMessage sm = (SessionMessage) message;
            logger.session(context, stateID, sm);

            eventID = sm.eventID;
            nextMessage = sm.message;
            replyCtx = sm.replyCtx;

            int oldState = stateID;

            Transition t = tMap[stateID][eventID];
            eventID = t.invoke(context, this);
            stateID = context.getStateID();

            replyCtx = null;

            logger.transition(context, oldState, stateID, eventID, nextMessage);
        } else {
            throw new RuntimeException("Internal FSM error.");
        }

        while (eventID != END_OF_TRANSITION) {
            if (stateID == endStateID) {
                logger.ignored(context, stateID, eventID);
                break;
            }
            int oldState = stateID;

            Transition t = tMap[stateID][eventID];
            eventID = t.invoke(context, this);
            stateID = context.getStateID();

            logger.transition(context, oldState, stateID, eventID, nextMessage);
        }
    }

    public String toDebugString() {
        return "";
    }
}
